﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Globalization;

namespace ArgusLib.Reflection
{
	public class AssemblyDependencies
	{
		public string[] AssemblyFiles { get; private set; }
		public KeyValuePair<string, string[]>[] SatelliteAssemblyFiles { get; private set; }

		private AssemblyDependencies() { }

		public static AssemblyDependencies GetDependencies(Assembly assembly)
		{
			List<string> assemblyFiles = new List<string>();
			Dictionary<string, List<string>> satAssemblyFiles = new Dictionary<string, List<string>>();
			List<Assembly> assemblies = new List<Assembly>();
			List<Assembly> satAssemblies = new List<Assembly>();
			assemblies.Add(assembly);
			for (int i = 0; i < assemblies.Count; i++)
			{
				assembly = assemblies[i];
				if (assembly.GlobalAssemblyCache == true)
					continue;

				assemblyFiles.Add(assembly.Location);

				string[] subdirs = Directory.GetDirectories(Path.GetDirectoryName(assembly.Location));
				foreach (string dir in subdirs)
				{
					int index = dir.LastIndexOf(Path.DirectorySeparatorChar);
					if (index < 0)
						continue;
					CultureInfo ci = new CultureInfo(dir.Substring(index + 1));
					Assembly sat;
					try { sat = assembly.GetSatelliteAssembly(ci); }
					catch (FileNotFoundException) { continue; }
					if (satAssemblies.Contains(sat) == false)
					{
						satAssemblies.Add(sat);
						if (satAssemblyFiles.ContainsKey(ci.Name) == false)
							satAssemblyFiles.Add(ci.Name, new List<string>());
						satAssemblyFiles[ci.Name].Add(sat.Location);
					}
				}

				string[] resNames = assembly.GetManifestResourceNames();
				foreach (string resName in resNames)
				{
					ManifestResourceInfo mri = assembly.GetManifestResourceInfo(resName);
					if (mri.ReferencedAssembly != null && assemblies.Contains(mri.ReferencedAssembly) == false)
						assemblies.Add(mri.ReferencedAssembly);
				}

				AssemblyName[] names = assembly.GetReferencedAssemblies();
				foreach (AssemblyName name in names)
				{
					Assembly a = Assembly.Load(name);
					if (a.GlobalAssemblyCache == true)
						continue;
					if (assemblies.Contains(a) == false)
						assemblies.Add(a);
				}
			}
			AssemblyDependencies dep = new AssemblyDependencies();
			dep.AssemblyFiles = assemblyFiles.ToArray();
			List<KeyValuePair<string, string[]>> tempList = new List<KeyValuePair<string, string[]>>();
			foreach (KeyValuePair<string, List<string>> item in satAssemblyFiles)
				tempList.Add(new KeyValuePair<string, string[]>(item.Key, item.Value.ToArray()));
			dep.SatelliteAssemblyFiles = tempList.ToArray();
			return dep;
		}
	}
}
